package com.moyun.service.upload.Impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.moyun.model.po.upload.SysAttachmentEntity;
import com.moyun.mapper.upload.SysAttachmentMapper;
import com.moyun.service.upload.SysAttachmentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.disk.DiskFileItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author yangboxuan
 * @since 2021-07-13
 */
@Slf4j
@Service
public class SysAttachmentServiceImpl extends ServiceImpl<SysAttachmentMapper, SysAttachmentEntity> implements SysAttachmentService {

    @Autowired
    private Environment env;
    @Autowired
    private SysAttachmentMapper sysAttachmentMapper;

    @Override
    public boolean upload(MultipartFile[] files, String docunid, String attType, Integer width, Integer height) throws IOException {

        Integer affectedRows = 0;
        for (MultipartFile multipartFile : files) {
            /**
             * 1. 获取原始文件名
             * 2. 获取文件大小
             * 3. 获取文件扩展名
             * 4. 生成新的文件名(32位UUID+文件扩展名)
             * 5. 获取文件保存路径
             * 6. 获取新的文件(File) 对象
             * 7. 获取文件类型
             */
            String originalFileName = multipartFile.getOriginalFilename();
            String fileSize = getPrintSize(multipartFile.getSize());
            String fileExtension = FileUtil.extName(originalFileName);
            String uuid = IdUtil.simpleUUID();
            String newFileName = uuid + "." + fileExtension;
            String contentType = multipartFile.getContentType();
            String fileType = null;
            // 获取文件保存路径
            String fileSavePath = this.env.getProperty("file.save-path");
            File file = new File(fileSavePath);

            // 文件写入
            try {
                if (!file.isDirectory()) {
                    file.mkdirs();
                }
                File fileTemp = new File(fileSavePath, newFileName);
                multipartFile.transferTo(fileTemp);
                fileType = FileUtil.getType(fileTemp);
            } catch (IOException e) {
                log.error(e.toString(), e);
                return false;
            }


            // 保存文件信息到数据库中
            SysAttachmentEntity sysAttachmentEntity = new SysAttachmentEntity();
            sysAttachmentEntity
                    .setUuid(uuid)
                    .setDocunid(docunid)
                    .setOriginalFileName(originalFileName)
                    .setType(fileType)
                    .setRelativePath(fileSavePath)
                    .setFileSize(fileSize)
                    .setFileExtension(fileExtension);
            int insert = this.sysAttachmentMapper.insert(sysAttachmentEntity);
            affectedRows += insert;
        }

        return affectedRows == files.length;

    }

    /**
     * @return boolean
     * @Author yangboxuan
     * @Description 文件下载
     * @Date 2021/7/21 10:32
     * @Param []
     **/
    @Override
    public void download(String fileName, HttpServletResponse response) throws IOException {
        // 获取文件保存路径
        String filePath = this.env.getProperty("file.save-path");
        // 从请求中获取文件名
        // 创建输出流对象
        ServletOutputStream outputStream = response.getOutputStream();
        // 以字节数组的形式读取文件
        byte[] bytes = FileUtil.readBytes(filePath + fileName);
        // 设置返回内容格式
        response.setContentType("application/octet-stream");

        // 把文件名按UTF-8取出并按ISO8859-1编码，保证弹出窗口中的文件名中文不乱码
        // 中文不要太多，最多支持17个中文，因为header有150个字节限制。
        // 这一步一定要在读取文件之后进行，否则文件名会乱码，找不到文件
        fileName = new String(fileName.getBytes("UTF-8"),"ISO8859-1");

        // 设置下载弹窗的文件名和格式（文件名要包括名字和文件格式）
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);

        // 返回数据到输出流对象中
        outputStream.write(bytes);

        // 关闭流对象
        IoUtil.close(outputStream);

    }

    /**
     * @return java.io.File
     * @Author yangboxuan
     * @Description 将 MultipartFile 文件转换为 File
     * @Date 2021/7/13 17:24
     * @Param [multipartFile]
     **/
    public static File multipartFile2File(MultipartFile multipartFile) throws IOException {

        //不生成临时文件，直接转换
        if (!multipartFile.isEmpty()) {

            CommonsMultipartFile cf = (CommonsMultipartFile) multipartFile;
            DiskFileItem fi = (DiskFileItem) cf.getFileItem();
            File file = fi.getStoreLocation();
            //如果不需要File文件可删除
            /*if(file.exists()){
                file.delete();
            }*/
            return file;
        } else {
            return null;
        }
    }

    /**
     * @return java.lang.String
     * @Author yangboxuan
     * @Description 获取文件大小 自动转换 B KB MB GB
     * @Date 2021/7/13 16:58
     * @Param [size]
     **/
    public static String getPrintSize(long size) {
        // 如果字节数少于1024，则直接以B为单位，否则先除于1024，后3位因太少无意义
        double value = (double) size;
        if (value < 1024) {
            return value + "B";
        } else {
            value = new BigDecimal(value / 1024).setScale(2, BigDecimal.ROUND_DOWN).doubleValue();
        }
        // 如果原字节数除于1024之后，少于1024，则可以直接以KB作为单位
        // 因为还没有到达要使用另一个单位的时候
        // 接下去以此类推
        if (value < 1024) {
            return value + "KB";
        } else {
            value = new BigDecimal(value / 1024).setScale(2, BigDecimal.ROUND_DOWN).doubleValue();
        }
        if (value < 1024) {
            return value + "MB";
        } else {
            // 否则如果要以GB为单位的，先除于1024再作同样的处理
            value = new BigDecimal(value / 1024).setScale(2, BigDecimal.ROUND_DOWN).doubleValue();
            return value + "GB";
        }
    }


}
